<!-- public/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>HLS.js API 详细说明</title>
    <style>
      body {
        font-family: Arial;
        padding: 20px;
      }
      video {
        width: 100%;
        max-width: 800px;
      }
      button {
        padding: 10px;
        margin-right: 10px;
        margin-bottom: 10px;
      }
      pre {
        background-color: #f5f5f5;
        padding: 10px;
        border-radius: 5px;
        overflow-x: auto;
        font-size: 14px;
        line-height: 1.5;
      }
      .api-section {
        margin-top: 30px;
        border-top: 1px solid #ddd;
        padding-top: 20px;
      }
      .api-title {
        font-weight: bold;
        margin-bottom: 10px;
        font-size: 18px;
        color: #2c3e50;
      }
      .api-description {
        margin-bottom: 15px;
        line-height: 1.6;
      }
      .property {
        margin-bottom: 15px;
        padding-left: 15px;
        border-left: 3px solid #3498db;
      }
      .property-name {
        font-weight: bold;
        color: #2980b9;
      }
      .property-type {
        color: #e74c3c;
        font-style: italic;
      }
      .property-default {
        color: #27ae60;
      }
      .property-description {
        margin-top: 5px;
      }
      .video-container {
        margin-bottom: 30px;
      }
      h1 {
        color: #2c3e50;
        border-bottom: 2px solid #3498db;
        padding-bottom: 10px;
      }
      h2 {
        color: #2c3e50;
        margin-top: 30px;
      }
      .control-group {
        margin-bottom: 15px;
        display: flex;
        align-items: center;
        gap: 10px;
      }
      .control-group label {
        min-width: 80px;
        font-weight: bold;
      }
      .control-group input[type="range"] {
        width: 200px;
      }
      .control-group select {
        min-width: 150px;
        padding: 5px;
      }
      #playbackInfo {
        background-color: #f8f9fa;
        padding: 15px;
        border-radius: 5px;
        border-left: 4px solid #3498db;
      }
      #playbackInfo div {
        margin-bottom: 5px;
      }
      .status-label {
        font-weight: bold;
        color: #2c3e50;
      }
    </style>
  </head>
  <body>
    <h1>HLS.js API 详细说明</h1>
    
    <div class="video-container">
      <h2>HLS 播放器演示</h2>
      <div class="control-group">
        <button onclick="playVideo()">开始播放视频</button>
        <button onclick="pauseVideo()">暂停/播放</button>
        <button onclick="muteVideo()">静音/取消静音</button>
      </div>

      <div class="control-group">
        <label for="volumeSlider">音量控制:</label>
        <input type="range" id="volumeSlider" min="0" max="100" value="50" onchange="setVolume(this.value)">
        <span id="volumeDisplay">50%</span>
      </div>

      <div class="control-group">
        <label for="qualitySelect">质量选择:</label>
        <select id="qualitySelect" onchange="setQuality(this.value)">
          <option value="-1">自动</option>
        </select>
        <span id="currentQuality">当前: 自动</span>
      </div>

      <video width="800" height="450" id="video" controls></video>

      <div style="margin-top: 15px;">
        <div class="status-label">播放状态信息:</div>
        <div id="playbackInfo">
          <div><strong>当前质量级别:</strong> <span id="currentLevelInfo">-</span></div>
          <div><strong>估计带宽:</strong> <span id="bandwidthInfo">-</span></div>
          <div><strong>缓冲区长度:</strong> <span id="bufferInfo">-</span></div>
          <div><strong>播放时间:</strong> <span id="timeInfo">-</span></div>
          <div><strong>音量:</strong> <span id="volumeInfo">50%</span></div>
        </div>
      </div>
    </div>
    
    <div id="hlsApiDocs">
      <h2>HLS.js 配置选项详解</h2>
      <div class="api-description">
        HLS.js 是一个强大的HTTP Live Streaming客户端，提供了丰富的配置选项来控制视频播放行为。
        以下是各个配置选项的详细说明，包括它们的作用、默认值和使用场景。
      </div>
      
      <div class="api-section">
        <div class="api-title">自适应比特率(ABR)相关配置</div>
        <div class="api-description">
          这些选项控制HLS.js如何根据网络条件自动调整视频质量，以提供流畅的播放体验。
        </div>
        
        <div class="property">
          <div class="property-name">startLevel</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: -1</div>
          <div class="property-description">
            设置初始播放的质量级别。-1表示自动选择，0表示最低质量，n表示第n个质量级别。<br>
            <strong>作用</strong>: 控制视频开始播放时使用的质量级别。当网络条件未知时，可以先选择较低质量开始播放，然后再逐渐提高质量。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">abrEwmaDefaultEstimate</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 1000000 (1Mbps)</div>
          <div class="property-description">
            默认带宽估计值(比特/秒)，当没有带宽历史数据时使用。<br>
            <strong>作用</strong>: 在播放开始时，HLS.js没有网络带宽信息，此值用作初始估计，影响首次质量级别选择。设置合理的默认值可以减少初始缓冲时间。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">abrEwmaFastLive</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 3.0</div>
          <div class="property-description">
            快速带宽估计的EWMA(指数加权移动平均)系数。<br>
            <strong>作用</strong>: 控制带宽估计对最近网络变化的敏感度。较小的值使系统对网络变化反应更快，但可能导致频繁切换质量级别。在直播场景中特别重要。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">abrEwmaSlowLive</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 9.0</div>
          <div class="property-description">
            慢速带宽估计的EWMA系数。<br>
            <strong>作用</strong>: 提供更稳定的长期带宽估计。较大的值会产生更平滑的带宽估计，减少质量级别的频繁切换，但对网络变化的反应会较慢。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">abrBandWidthFactor</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 0.95</div>
          <div class="property-description">
            带宽因子，用于计算下一个级别。<br>
            <strong>作用</strong>: 这是一个安全系数，实际使用的带宽估计值会乘以这个因子。例如，如果估计带宽是10Mbps，实际用于决策的带宽是9.5Mbps。这样可以留出一些余量，避免选择过高的质量级别导致卡顿。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">abrBandWidthUpFactor</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 0.7</div>
          <div class="property-description">
            带宽上升因子，用于计算升级到更高质量级别时的阈值。<br>
            <strong>作用</strong>: 控制升级到更高质量级别的激进程度。值越低，越容易升级到更高质量。这个值小于abrBandWidthFactor，意味着升级比降级需要更严格的条件，这有助于防止频繁的质量级别切换。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">abrMaxWithRealBitrate</div>
          <div class="property-type">类型: Boolean</div>
          <div class="property-default">默认值: false</div>
          <div class="property-description">
            是否使用实际测量的比特率而不是清单中声明的比特率。<br>
            <strong>作用</strong>: 当设为true时，HLS.js会使用实际下载片段的比特率来更新带宽估计，而不是使用清单中声明的比特率。这在清单中的比特率不准确时很有用。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">maxStarvationDelay</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 4 (秒)</div>
          <div class="property-description">
            最大饥饿延迟，即缓冲区为空时等待的最长时间。<br>
            <strong>作用</strong>: 当缓冲区为空时，播放器会等待一段时间再尝试加载更多内容。这个值控制最长等待时间，超过这个时间后，播放器会尝试降低质量级别以加快加载速度。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">maxLoadingDelay</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 4 (秒)</div>
          <div class="property-description">
            最大加载延迟，即加载片段的最长等待时间。<br>
            <strong>作用</strong>: 控制加载片段的超时时间。如果片段加载时间超过这个值，播放器会考虑降低质量级别。这有助于在网络条件变差时快速响应。
          </div>
        </div>

        <div class="property">
          <div class="property-name">abrEwmaFastVoD</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 3.0</div>
          <div class="property-description">
            点播内容的快速带宽估计EWMA系数。<br>
            <strong>作用</strong>: 与abrEwmaFastLive类似，但专门用于点播(VoD)内容。点播内容通常网络条件更稳定，可以使用不同的参数优化。
          </div>
        </div>

        <div class="property">
          <div class="property-name">abrEwmaSlowVoD</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 9.0</div>
          <div class="property-description">
            点播内容的慢速带宽估计EWMA系数。<br>
            <strong>作用</strong>: 为点播内容提供更稳定的长期带宽估计，通常比直播内容允许更平滑的质量切换。
          </div>
        </div>

        <div class="property">
          <div class="property-name">maxMaxBufferLength</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 600 (秒)</div>
          <div class="property-description">
            最大缓冲区长度的上限。<br>
            <strong>作用</strong>: 即使在网络条件很好的情况下，也限制缓冲区不能超过这个时间长度。防止过度缓冲占用太多内存和带宽。
          </div>
        </div>
      </div>
      
      <div class="api-section">
        <div class="api-title">缓冲区相关配置</div>
        <div class="api-description">
          这些选项控制视频缓冲的行为，影响播放流畅度和内存使用。
        </div>
        
        <div class="property">
          <div class="property-name">maxBufferLength</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 30 (秒)</div>
          <div class="property-description">
            最大缓冲区长度，以秒为单位。<br>
            <strong>作用</strong>: 控制播放器最多预加载多少秒的视频内容。较大的值可以减少网络波动带来的影响，但会增加内存使用。在网络不稳定的环境中，增加这个值可以提高播放流畅度。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">maxBufferSize</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 60 * 1000 * 1000 (60MB)</div>
          <div class="property-description">
            最大缓冲区大小，以字节为单位。<br>
            <strong>作用</strong>: 限制缓冲区占用的最大内存。当缓冲的数据超过这个大小时，播放器会停止加载更多内容，直到缓冲区大小减小。这对于移动设备等内存受限的环境特别重要。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">maxBufferHole</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 0.5 (秒)</div>
          <div class="property-description">
            最大缓冲区空洞，即可以忽略的缓冲区中的小间隙。<br>
            <strong>作用</strong>: 当缓冲区中存在小于此值的间隙时，播放器会尝试跳过而不是停下来重新缓冲。这可以减少由于微小缓冲间隙导致的播放中断。
          </div>
        </div>

        <div class="property">
          <div class="property-name">lowBufferWatchdogPeriod</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 0.5 (秒)</div>
          <div class="property-description">
            低缓冲区监控周期。<br>
            <strong>作用</strong>: 控制检查缓冲区状态的频率。当缓冲区较低时，播放器会更频繁地检查是否需要加载更多内容。较小的值意味着更快的响应，但也会增加CPU使用。
          </div>
        </div>

        <div class="property">
          <div class="property-name">highBufferWatchdogPeriod</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 3 (秒)</div>
          <div class="property-description">
            高缓冲区监控周期。<br>
            <strong>作用</strong>: 当缓冲区充足时的检查频率。由于缓冲区充足，可以降低检查频率以节省资源。
          </div>
        </div>

        <div class="property">
          <div class="property-name">nudgeOffset</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 0.1 (秒)</div>
          <div class="property-description">
            微调偏移量，用于处理缓冲区边界问题。<br>
            <strong>作用</strong>: 当播放位置接近缓冲区边界时，添加一个小的偏移量以避免播放中断。这有助于处理浮点数精度问题和时间戳不准确的情况。
          </div>
        </div>

        <div class="property">
          <div class="property-name">nudgeMaxRetry</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 3</div>
          <div class="property-description">
            微调的最大重试次数。<br>
            <strong>作用</strong>: 当使用nudgeOffset仍无法解决播放问题时，最多重试的次数。超过这个次数后，播放器会采用其他恢复策略。
          </div>
        </div>
      </div>
      
      <div class="api-section">
        <div class="api-title">错误处理相关配置</div>
        <div class="api-description">
          这些选项控制HLS.js如何处理加载和解析过程中的各种错误。
        </div>
        
        <div class="property">
          <div class="property-name">manifestLoadingTimeOut</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 10000 (毫秒)</div>
          <div class="property-description">
            清单加载超时时间。<br>
            <strong>作用</strong>: 控制加载HLS清单文件的最大等待时间。如果超过这个时间还未加载完成，会触发超时错误。在网络条件较差的环境中，可以适当增加这个值。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">manifestLoadingMaxRetry</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 1</div>
          <div class="property-description">
            清单加载失败后的最大重试次数。<br>
            <strong>作用</strong>: 当清单加载失败时，HLS.js会自动重试。这个值控制最大重试次数，增加这个值可以提高在不稳定网络下的加载成功率。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">levelLoadingTimeOut</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 10000 (毫秒)</div>
          <div class="property-description">
            级别加载超时时间。<br>
            <strong>作用</strong>: 控制加载质量级别信息的最大等待时间。如果超时，播放器会尝试加载其他质量级别。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">fragLoadingTimeOut</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 20000 (毫秒)</div>
          <div class="property-description">
            片段加载超时时间。<br>
            <strong>作用</strong>: 控制加载视频片段的最大等待时间。如果片段加载时间超过这个值，会触发加载超时错误，播放器可能会尝试降低质量级别或重试。
          </div>
        </div>

        <div class="property">
          <div class="property-name">fragLoadingMaxRetry</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 3</div>
          <div class="property-description">
            片段加载失败后的最大重试次数。<br>
            <strong>作用</strong>: 当片段加载失败时，播放器会自动重试。这个值控制最大重试次数，有助于在网络不稳定时提高加载成功率。
          </div>
        </div>

        <div class="property">
          <div class="property-name">fragLoadingRetryDelay</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 1000 (毫秒)</div>
          <div class="property-description">
            片段加载重试延迟时间。<br>
            <strong>作用</strong>: 片段加载失败后，等待多长时间再进行重试。适当的延迟可以避免在网络问题期间过于频繁的重试。
          </div>
        </div>

        <div class="property">
          <div class="property-name">levelLoadingMaxRetry</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 4</div>
          <div class="property-description">
            级别加载失败后的最大重试次数。<br>
            <strong>作用</strong>: 当质量级别信息加载失败时的重试次数。这对于确保播放器能够获取到可用的质量级别信息很重要。
          </div>
        </div>

        <div class="property">
          <div class="property-name">levelLoadingRetryDelay</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 1000 (毫秒)</div>
          <div class="property-description">
            级别加载重试延迟时间。<br>
            <strong>作用</strong>: 级别加载失败后的重试等待时间，避免过于频繁的重试请求。
          </div>
        </div>
      </div>

      <div class="api-section">
        <div class="api-title">高级配置选项</div>
        <div class="api-description">
          这些是一些高级配置选项，用于精细调优播放器的行为和性能。
        </div>

        <div class="property">
          <div class="property-name">enableWorker</div>
          <div class="property-type">类型: Boolean</div>
          <div class="property-default">默认值: true</div>
          <div class="property-description">
            是否启用Web Worker进行片段解析。<br>
            <strong>作用</strong>: 启用后，片段的解析工作会在Web Worker中进行，避免阻塞主线程，提高播放性能。在低端设备上可能需要禁用以节省资源。
          </div>
        </div>

        <div class="property">
          <div class="property-name">enableSoftwareAES</div>
          <div class="property-type">类型: Boolean</div>
          <div class="property-default">默认值: true</div>
          <div class="property-description">
            是否启用软件AES解密。<br>
            <strong>作用</strong>: 当浏览器不支持硬件AES解密时，使用软件实现。对于加密的HLS流，这个选项确保在所有浏览器中都能正常播放。
          </div>
        </div>

        <div class="property">
          <div class="property-name">forceKeyFrameOnDiscontinuity</div>
          <div class="property-type">类型: Boolean</div>
          <div class="property-default">默认值: true</div>
          <div class="property-description">
            在不连续点强制关键帧。<br>
            <strong>作用</strong>: 在流的不连续点（如广告插入点）强制使用关键帧，确保播放的连续性和质量。
          </div>
        </div>

        <div class="property">
          <div class="property-name">appendErrorMaxRetry</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 3</div>
          <div class="property-description">
            媒体数据追加错误的最大重试次数。<br>
            <strong>作用</strong>: 当向MediaSource追加数据失败时的重试次数。这有助于处理浏览器MediaSource API的临时错误。
          </div>
        </div>

        <div class="property">
          <div class="property-name">liveSyncDurationCount</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: 3</div>
          <div class="property-description">
            直播同步持续时间计数。<br>
            <strong>作用</strong>: 控制直播流中用于同步的片段数量。较大的值提供更好的缓冲，但会增加延迟。
          </div>
        </div>

        <div class="property">
          <div class="property-name">liveMaxLatencyDurationCount</div>
          <div class="property-type">类型: Number</div>
          <div class="property-default">默认值: Infinity</div>
          <div class="property-description">
            直播最大延迟持续时间计数。<br>
            <strong>作用</strong>: 控制直播流允许的最大延迟。当延迟超过这个值时，播放器会尝试跳到更接近直播边缘的位置。
          </div>
        </div>
      </div>

      <div class="api-section">
        <div class="api-title">HLS.js 主要属性及其作用</div>
        <div class="api-description">
          以下是HLS.js实例的主要属性，这些属性可以用来获取播放状态和控制播放行为。
        </div>
        
        <div class="property">
          <div class="property-name">hls.levels</div>
          <div class="property-type">类型: Array</div>
          <div class="property-description">
            可用的质量级别数组。<br>
            <strong>作用</strong>: 包含所有可用的视频质量级别信息，每个级别包含分辨率、比特率等信息。可以通过查看这个属性了解当前流提供的所有质量选项。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">hls.currentLevel</div>
          <div class="property-type">类型: Number</div>
          <div class="property-description">
            当前播放的质量级别索引。<br>
            <strong>作用</strong>: 获取或设置当前播放的质量级别。设置为-1启用自动级别选择，设置为0到levels.length-1之间的值可以强制使用特定质量级别。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">hls.autoLevelEnabled</div>
          <div class="property-type">类型: Boolean</div>
          <div class="property-description">
            是否启用自动质量级别选择。<br>
            <strong>作用</strong>: 只读属性，表示当前是否启用了自动质量级别选择。当hls.currentLevel设为-1时，此值为true。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">hls.bandwidthEstimate</div>
          <div class="property-type">类型: Number</div>
          <div class="property-description">
            当前带宽估计值(比特/秒)。<br>
            <strong>作用</strong>: 获取HLS.js当前估计的网络带宽，这个值用于自动选择合适的质量级别。可以监控这个值来了解当前网络状况。
          </div>
        </div>
      </div>
      
      <div class="api-section">
        <div class="api-title">HLS.js 主要方法及其作用</div>
        <div class="api-description">
          以下是HLS.js实例提供的主要方法，用于控制播放和处理各种场景。
        </div>
        
        <div class="property">
          <div class="property-name">hls.loadSource(url)</div>
          <div class="property-description">
            加载HLS流。<br>
            <strong>作用</strong>: 开始加载指定URL的HLS流。这通常是使用HLS.js的第一步，在attachMedia之后调用。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">hls.startLoad(startPosition)</div>
          <div class="property-description">
            开始加载媒体片段。<br>
            <strong>作用</strong>: 开始或恢复加载媒体片段。startPosition参数可选，指定开始播放的位置（秒）。如果之前调用了stopLoad，可以使用这个方法恢复加载。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">hls.stopLoad()</div>
          <div class="property-description">
            停止加载媒体片段。<br>
            <strong>作用</strong>: 停止加载更多的媒体片段，但不会停止当前播放。这在需要暂时暂停加载（例如用户切换到后台）时很有用，可以节省带宽。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">hls.recoverMediaError()</div>
          <div class="property-description">
            恢复媒体错误。<br>
            <strong>作用</strong>: 尝试从媒体错误中恢复。当播放过程中出现媒体错误时，可以调用此方法尝试恢复播放，而不是完全重新加载。
          </div>
        </div>
      </div>
      
      <div class="api-section">
        <div class="api-title">HLS.js 主要事件及其作用</div>
        <div class="api-description">
          HLS.js提供了丰富的事件系统，可以用来监控播放状态和处理各种情况。
        </div>
        
        <div class="property">
          <div class="property-name">Hls.Events.MANIFEST_PARSED</div>
          <div class="property-description">
            清单已解析事件。<br>
            <strong>作用</strong>: 当HLS清单文件加载并解析完成时触发。此时可以获取到所有可用的质量级别信息，通常在这个事件之后开始播放视频。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">Hls.Events.LEVEL_SWITCHED</div>
          <div class="property-description">
            级别已切换事件。<br>
            <strong>作用</strong>: 当播放器切换到不同的质量级别时触发。可以监听这个事件来了解当前播放的质量级别变化，例如显示当前分辨率信息。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">Hls.Events.ERROR</div>
          <div class="property-description">
            错误事件。<br>
            <strong>作用</strong>: 当播放过程中发生错误时触发。事件数据包含错误类型和详细信息，可以根据这些信息进行相应的错误处理和恢复。
          </div>
        </div>
        
        <div class="property">
          <div class="property-name">Hls.Events.FRAG_LOADED</div>
          <div class="property-description">
            片段已加载事件。<br>
            <strong>作用</strong>: 当一个媒体片段加载完成时触发。可以用来监控加载进度和计算实际带宽。
          </div>
        </div>
      </div>

      <div class="api-section">
        <div class="api-title">音量和播放控制</div>
        <div class="api-description">
          虽然HLS.js主要负责流媒体处理，但可以通过HTML5 video元素实现完整的播放控制功能。
        </div>

        <div class="property">
          <div class="property-name">video.volume</div>
          <div class="property-type">类型: Number (0.0 - 1.0)</div>
          <div class="property-description">
            控制视频音量，0.0为静音，1.0为最大音量。<br>
            <strong>示例</strong>: video.volume = 0.5 // 设置音量为50%
          </div>
        </div>

        <div class="property">
          <div class="property-name">video.muted</div>
          <div class="property-type">类型: Boolean</div>
          <div class="property-description">
            控制视频静音状态。<br>
            <strong>示例</strong>: video.muted = true // 静音
          </div>
        </div>

        <div class="property">
          <div class="property-name">hls.currentLevel</div>
          <div class="property-type">类型: Number</div>
          <div class="property-description">
            手动设置播放质量级别。<br>
            <strong>示例</strong>: hls.currentLevel = 2 // 切换到第3个质量级别<br>
            <strong>示例</strong>: hls.currentLevel = -1 // 启用自动质量选择
          </div>
        </div>

        <div class="property">
          <div class="property-name">播放状态监控</div>
          <div class="property-description">
            可以通过以下属性监控播放状态：<br>
            • hls.levels - 获取所有可用质量级别<br>
            • hls.currentLevel - 当前质量级别<br>
            • hls.bandwidthEstimate - 当前带宽估计<br>
            • video.buffered - 缓冲区信息<br>
            • video.currentTime - 当前播放时间<br>
            • video.duration - 视频总时长
          </div>
        </div>
      </div>

      <div class="api-section">
        <div class="api-title">配置最佳实践和使用场景</div>
        <div class="api-description">
          根据不同的使用场景，以下是一些推荐的配置组合和最佳实践。
        </div>

        <div class="property">
          <div class="property-name">移动设备优化配置</div>
          <div class="property-description">
            <strong>场景</strong>: 移动设备，网络不稳定，内存受限<br>
            <strong>推荐配置</strong>:<br>
            • maxBufferLength: 15 (减少内存使用)<br>
            • maxBufferSize: 30 * 1000 * 1000 (30MB，适合移动设备)<br>
            • abrEwmaFastLive: 2.0 (更快响应网络变化)<br>
            • fragLoadingMaxRetry: 5 (增加重试次数)<br>
            • enableWorker: false (在低端设备上可能更稳定)
          </div>
        </div>

        <div class="property">
          <div class="property-name">直播流优化配置</div>
          <div class="property-description">
            <strong>场景</strong>: 直播内容，低延迟要求<br>
            <strong>推荐配置</strong>:<br>
            • liveSyncDurationCount: 2 (减少延迟)<br>
            • liveMaxLatencyDurationCount: 5 (控制最大延迟)<br>
            • maxBufferLength: 10 (减少缓冲延迟)<br>
            • abrEwmaFastLive: 2.0 (快速适应网络变化)<br>
            • maxStarvationDelay: 2 (快速响应缓冲不足)
          </div>
        </div>

        <div class="property">
          <div class="property-name">点播内容优化配置</div>
          <div class="property-description">
            <strong>场景</strong>: 点播内容，追求播放流畅度<br>
            <strong>推荐配置</strong>:<br>
            • maxBufferLength: 60 (增加缓冲以提高流畅度)<br>
            • maxBufferSize: 120 * 1000 * 1000 (120MB，更大缓冲)<br>
            • abrEwmaSlowVoD: 15.0 (更稳定的质量切换)<br>
            • fragLoadingTimeOut: 30000 (更长的超时时间)<br>
            • maxStarvationDelay: 6 (允许更长的恢复时间)
          </div>
        </div>

        <div class="property">
          <div class="property-name">网络不稳定环境配置</div>
          <div class="property-description">
            <strong>场景</strong>: 网络条件差，频繁波动<br>
            <strong>推荐配置</strong>:<br>
            • abrBandWidthFactor: 0.8 (更保守的带宽估计)<br>
            • abrBandWidthUpFactor: 0.5 (更严格的升级条件)<br>
            • fragLoadingMaxRetry: 6 (增加重试次数)<br>
            • manifestLoadingMaxRetry: 3 (增加清单重试)<br>
            • fragLoadingRetryDelay: 2000 (增加重试间隔)
          </div>
        </div>
      </div>
    </div>

    <script src="/js/hls.js"></script>
    <script>
      const playlistUrl = "/adaptive/input3/stream_1280_720/index.m3u8"
      const video = document.getElementById("video")
      let hls

      // 初始化 HLS 播放器
      if (Hls.isSupported()) {
        hls = new Hls({
          // 自适应比特率(ABR)配置
          startLevel: -1,                // 初始加载级别，-1表示自动选择
          abrEwmaDefaultEstimate: 1000000, // 默认带宽估计值(比特/秒)，1Mbps
          abrEwmaFastLive: 3.0,          // 快速带宽估计的EWMA系数
          abrEwmaSlowLive: 9.0,          // 慢速带宽估计的EWMA系数
          abrEwmaFastVoD: 3.0,           // 点播内容的快速EWMA系数
          abrEwmaSlowVoD: 9.0,           // 点播内容的慢速EWMA系数
          abrBandWidthFactor: 0.95,      // 带宽安全系数
          abrBandWidthUpFactor: 0.7,     // 升级带宽系数
          abrMaxWithRealBitrate: false,  // 是否使用实际比特率

          // 缓冲区配置
          maxBufferLength: 30,           // 最大缓冲区长度(秒)
          maxBufferSize: 60 * 1000 * 1000, // 最大缓冲区大小(字节)，60MB
          maxBufferHole: 0.5,            // 最大缓冲区空洞(秒)
          maxMaxBufferLength: 600,       // 最大缓冲区长度上限(秒)
          lowBufferWatchdogPeriod: 0.5,  // 低缓冲区监控周期(秒)
          highBufferWatchdogPeriod: 3,   // 高缓冲区监控周期(秒)
          nudgeOffset: 0.1,              // 微调偏移量(秒)
          nudgeMaxRetry: 3,              // 微调最大重试次数

          // 错误处理配置
          maxStarvationDelay: 4,         // 最大饥饿延迟(秒)
          maxLoadingDelay: 4,            // 最大加载延迟(秒)
          manifestLoadingTimeOut: 10000, // 清单加载超时(毫秒)
          manifestLoadingMaxRetry: 1,    // 清单加载最大重试次数
          levelLoadingTimeOut: 10000,    // 级别加载超时(毫秒)
          levelLoadingMaxRetry: 4,       // 级别加载最大重试次数
          levelLoadingRetryDelay: 1000,  // 级别加载重试延迟(毫秒)
          fragLoadingTimeOut: 20000,     // 片段加载超时(毫秒)
          fragLoadingMaxRetry: 3,        // 片段加载最大重试次数
          fragLoadingRetryDelay: 1000,   // 片段加载重试延迟(毫秒)

          // 高级配置
          enableWorker: true,            // 启用Web Worker
          enableSoftwareAES: true,       // 启用软件AES解密
          forceKeyFrameOnDiscontinuity: true, // 不连续点强制关键帧
          appendErrorMaxRetry: 3,        // 媒体追加错误最大重试次数
          liveSyncDurationCount: 3,      // 直播同步持续时间计数
          liveMaxLatencyDurationCount: Infinity, // 直播最大延迟持续时间计数

          // 调试配置
          debug: false                   // 是否启用调试模式
        })

        hls.attachMedia(video)

        // 设置初始音量
        video.volume = 0.5

        // 监听事件
        hls.on(Hls.Events.MANIFEST_PARSED, function () {
          console.log("播放列表已解析，发现 " + hls.levels.length + " 种质量级别")

          // 填充质量选择下拉框
          const qualitySelect = document.getElementById('qualitySelect')
          qualitySelect.innerHTML = '<option value="-1">自动</option>'

          hls.levels.forEach((level, index) => {
            const option = document.createElement('option')
            option.value = index
            option.textContent = `${level.width}x${level.height} (${Math.round(level.bitrate/1000)} kbps)`
            qualitySelect.appendChild(option)
          })
        })
        
        // 监听级别切换事件
        hls.on(Hls.Events.LEVEL_SWITCHED, function(event, data) {
          if (hls.levels && hls.levels[data.level]) {
            const level = hls.levels[data.level];
            console.log(`切换到质量级别: ${level.width}x${level.height}, ${Math.round(level.bitrate/1000)} kbps`);

            // 更新质量选择下拉框的显示
            const qualitySelect = document.getElementById('qualitySelect')
            if (hls.autoLevelEnabled) {
              qualitySelect.value = '-1'
            } else {
              qualitySelect.value = data.level
            }

            // 立即更新播放状态信息
            updatePlaybackInfo()
          }
        });
        
        // 监听错误事件
        hls.on(Hls.Events.ERROR, function(event, data) {
          console.error(`HLS错误: ${data.type} - ${data.details}`);
          if (data.fatal) {
            switch (data.type) {
              case Hls.ErrorTypes.NETWORK_ERROR:
                console.log("网络错误，尝试恢复...");
                hls.startLoad();
                break;
              case Hls.ErrorTypes.MEDIA_ERROR:
                console.log("媒体错误，尝试恢复...");
                hls.recoverMediaError();
                break;
              default:
                console.log("无法恢复的错误，销毁播放器");
                hls.destroy();
                break;
            }
          }
        });
      } else {
        console.error("浏览器不支持HLS.js");
      }

      /**
       * 播放视频
       * 加载HLS流并开始播放
       */
      function playVideo() {
        if (hls) {
          hls.loadSource(playlistUrl)
          video.play()
        } else if (video.canPlayType("application/vnd.apple.mpegurl")) {
          video.src = playlistUrl
          video.play()
        } else {
          alert("您的浏览器不支持HLS视频播放");
        }
      }

      /**
       * 暂停视频
       */
      function pauseVideo() {
        if (video.paused) {
          video.play()
        } else {
          video.pause()
        }
      }

      /**
       * 静音/取消静音
       */
      function muteVideo() {
        video.muted = !video.muted
      }

      /**
       * 设置音量
       * @param {number} value - 音量值 (0-100)
       */
      function setVolume(value) {
        video.volume = value / 100
        document.getElementById('volumeDisplay').textContent = value + '%'
        document.getElementById('volumeInfo').textContent = value + '%'
      }

      /**
       * 设置视频质量
       * @param {string} levelIndex - 质量级别索引，-1为自动
       */
      function setQuality(levelIndex) {
        if (hls) {
          hls.currentLevel = parseInt(levelIndex)
          const currentQualitySpan = document.getElementById('currentQuality')
          if (levelIndex === '-1') {
            currentQualitySpan.textContent = '当前: 自动'
          } else {
            const level = hls.levels[levelIndex]
            if (level) {
              currentQualitySpan.textContent = `当前: ${level.width}x${level.height}`
            }
          }
        }
      }

      /**
       * 更新播放状态信息
       */
      function updatePlaybackInfo() {
        if (hls && hls.levels) {
          // 更新当前质量级别信息
          const currentLevelInfo = document.getElementById('currentLevelInfo')
          if (hls.autoLevelEnabled) {
            const level = hls.levels[hls.loadLevel]
            if (level) {
              currentLevelInfo.textContent = `自动 (${level.width}x${level.height})`
            } else {
              currentLevelInfo.textContent = '自动'
            }
          } else {
            const level = hls.levels[hls.currentLevel]
            if (level) {
              currentLevelInfo.textContent = `手动 (${level.width}x${level.height})`
            }
          }

          // 更新带宽信息
          const bandwidthInfo = document.getElementById('bandwidthInfo')
          if (hls.bandwidthEstimate) {
            bandwidthInfo.textContent = `${Math.round(hls.bandwidthEstimate / 1000)} kbps`
          }

          // 更新缓冲区信息
          const bufferInfo = document.getElementById('bufferInfo')
          if (video.buffered.length > 0) {
            const bufferedEnd = video.buffered.end(video.buffered.length - 1)
            const bufferLength = bufferedEnd - video.currentTime
            bufferInfo.textContent = `${bufferLength.toFixed(1)} 秒`
          }
        }

        // 更新播放时间信息
        const timeInfo = document.getElementById('timeInfo')
        if (video.duration) {
          const current = Math.floor(video.currentTime)
          const total = Math.floor(video.duration)
          const currentMin = Math.floor(current / 60)
          const currentSec = current % 60
          const totalMin = Math.floor(total / 60)
          const totalSec = total % 60
          timeInfo.textContent = `${currentMin}:${currentSec.toString().padStart(2, '0')} / ${totalMin}:${totalSec.toString().padStart(2, '0')}`
        }

        // 更新音量信息
        const volumeInfo = document.getElementById('volumeInfo')
        if (video.muted) {
          volumeInfo.textContent = '静音'
        } else {
          volumeInfo.textContent = `${Math.round(video.volume * 100)}%`
        }
      }

      // 定期更新播放状态信息
      setInterval(updatePlaybackInfo, 1000)
    </script>
  </body>
</html>
